package com.example.code.juc;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 集合类不安全问题
 * <p>
 * 1.故障现象 java.util.ConcurrentModificationException
 * 2.导致原因：并发争抢修改导致，一个线程在写，另一个线程争抢，导致数据不一致并发修改异常
 * 3.解决方案
 * 3.1 new Vector<>();
 * 3.2 Collections.synchronizedList(new ArrayList<>());
 * 3.3 new CopyOnWriteArrayList<>();
 */
public class ContainerNoSafeDemo {

    public static void main(String[] args) {
        // HashMap线程不安全
        Map<String, String> map = new HashMap<>();

        //juc包下的ConcurrentHashMap线程安全，采用的分段锁实现
        Map<String, String> concurrentHashMap = new ConcurrentHashMap<>();

        concurrentHashMap.put("", "");
    }

    public static void setNoSafe() {
        // HashSet的底层是HashMap,线程不安全
        Set<String> set = new HashSet<>();
//        Set<String> set = Collections.synchronizedSet(new HashSet<>());
        // CopyOnWriteArraySet 的底层其实还是一个CopyOnWriteArraySet，在add的时候进行了去重复的处理，循环遍历，如果有存在的返回false
//        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();

        System.out.println(set);
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                set.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(set);
            }, "").start();
        }
    }

    /**
     * List集合线程安全处理类
     */
    public static void listNoSafe() {
//        List<String> list = new ArrayList<>();
//        List<String> list = new Vector<>();
//        List<String> list = Collections.synchronizedList(new ArrayList<>());
        List<String> list = new CopyOnWriteArrayList<>();
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, "").start();
        }


    /*
    CopyOnWrite容器即写时复制的容器。待一个容器添加元素的时候，不直接往当前容器Object[]添加，
    而是先将当前容器Object[]进行copy，复制出一个新的容器Object[] newELements，然后新的容器Object[ ] newELements里添加元素，
    添加完元素之后，再将原容器的引用指向新的容器setArray (newELements)。

    这样做的好处是可以对CopyOnWrite容器进行并发的读，而不需要加锁（区别于Vector和Collections.synchronizedList()），
    因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想，读和写不同的容器。
     */
    }
}
